package utils

import (
	"crypto/aes"
	"crypto/cipher"
	"crypto/md5"
	"crypto/rand"
	"crypto/sha1"
	"crypto/sha256"
	"encoding/base64"
	"encoding/hex"
	"fmt"
	"io"

	"golang.org/x/crypto/bcrypt"
)

// Encrypt 加密
func Encrypt(plainText string, key string) (string, error) {
	// key 必须是 16, 24, 32 字节（AES-128/192/256）
	block, err := aes.NewCipher([]byte(key))
	if err != nil {
		return "", err
	}

	// 生成 GCM
	aesGCM, err := cipher.NewGCM(block)
	if err != nil {
		return "", err
	}

	// 生成随机 nonce
	nonce := make([]byte, aesGCM.NonceSize())
	if _, err = io.ReadFull(rand.Reader, nonce); err != nil {
		return "", err
	}

	// 加密（包含 nonce）
	cipherText := aesGCM.Seal(nonce, nonce, []byte(plainText), nil)

	// 返回 base64 编码
	return base64.StdEncoding.EncodeToString(cipherText), nil
}

// Decrypt 解密
func Decrypt(encryptedText string, key string) (string, error) {
	// base64 解码
	data, err := base64.StdEncoding.DecodeString(encryptedText)
	if err != nil {
		return "", err
	}

	block, err := aes.NewCipher([]byte(key))
	if err != nil {
		return "", err
	}

	aesGCM, err := cipher.NewGCM(block)
	if err != nil {
		return "", err
	}

	nonceSize := aesGCM.NonceSize()
	if len(data) < nonceSize {
		return "", fmt.Errorf("ciphertext too short")
	}

	nonce, cipherText := data[:nonceSize], data[nonceSize:]

	// 解密
	plainText, err := aesGCM.Open(nil, nonce, cipherText, nil)
	if err != nil {
		return "", err
	}

	return string(plainText), nil
}

func MD5(text string) string {
	return hex.EncodeToString(md5.New().Sum([]byte(text)))
}

func SHA1(text string) string {
	return hex.EncodeToString(sha1.New().Sum([]byte(text)))
}

func SHA256(text string) string {
	return hex.EncodeToString(sha256.New().Sum([]byte(text)))
}

// GenerateToken 生成Token
func GenerateToken() (string, error) {
	buf := make([]byte, 32)
	if _, err := rand.Read(buf); err != nil {
		return "", err
	}
	return hex.EncodeToString(buf), nil
}

// HashPassword 哈希密码
func HashPassword(password string) (string, error) {
	hash, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
	if err != nil {
		return "", err
	}
	return base64.StdEncoding.EncodeToString(hash), nil
}

// VerifyPassword 验证密码
func VerifyPassword(password string, hash string) error {
	hashBytes, err := base64.StdEncoding.DecodeString(hash)
	if err != nil {
		return err
	}
	return bcrypt.CompareHashAndPassword(hashBytes, []byte(password))
}
